/* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */

/* Tool adaptation: _size changed to size (freed the scope)... breaks everything else... unless it's really private  */

/* FIXME: assumes position styles are specified in 'px' */

ToolMan._coordinatesFactory = 
{

	create : function(x, y)
	{
		// FIXME: Safari won't parse 'throw' and aborts trying to do anything with this file
		//if (isNaN(x) || isNaN(y)) throw "invalid x,y: " + x + "," + y
		/// constructor was changed to not hold a pointer to the factory
		//return new _ToolManCoordinate(this, x, y);
		return new _ToolManCoordinate(x, y);
	},

	origin : function()
	{
		return this.create(0, 0);
	},

	/*
	 * FIXME: Safari 1.2, returns (0,0) on absolutely positioned elements
	 */
	topLeftPosition : function(element)
	{
		var left = parseInt(ToolMan.css().readStyle(element, "left"));
		var left = isNaN(left) ? 0 : left;
		var top = parseInt(ToolMan.css().readStyle(element, "top"));
		var top = isNaN(top) ? 0 : top;

		return this.create(left, top);
	},

	bottomRightPosition : function(element)
	{
		return this.topLeftPosition(element).plus(this._size(element));
	},

	topLeftOffset : function(element)
	{
		var offset = this._offset(element);

		var parent = element.offsetParent;
		while (parent)
		{
			offset = offset.plus(this._offset(parent));
			parent = parent.offsetParent;
		}
		return offset;
	},

	bottomRightOffset : function(element)
	{
		return this.topLeftOffset(element).plus
		(
			this.create(element.offsetWidth, element.offsetHeight)
		);
	},

	scrollOffset : function()
	{
		if (window.pageXOffset)
		{
			return this.create(window.pageXOffset, window.pageYOffset);
		} else if (document.documentElement)
		{
			return this.create(
					document.body.scrollLeft + document.documentElement.scrollLeft,
					document.body.scrollTop + document.documentElement.scrollTop);
		} else if (document.body.scrollLeft >= 0)
		{
			return this.create(document.body.scrollLeft, document.body.scrollTop);
		} else
		{
			return this.create(0, 0);
		}
	},

	clientSize : function()
	{
		if (window.innerHeight >= 0)
		{
			return this.create(window.innerWidth, window.innerHeight);
		} else if (document.documentElement)
		{
			return this.create(document.documentElement.clientWidth,
					document.documentElement.clientHeight);
		} else if (document.body.clientHeight >= 0)
		{
			return this.create(document.body.clientWidth,
					document.body.clientHeight);
		} else
		{
			return this.create(0, 0);
		}
	},

	/**
	 * mouse coordinate relative to the window (technically the
	 * browser client area) i.e. the part showing your page
	 *
	 * NOTE: in Safari the coordinate is relative to the document
	 */
	mousePosition : function(event)
	{
		event = ToolMan.events().fix(event);
		return this.create(event.clientX, event.clientY);
	},

	/**
	 * mouse coordinate relative to the document
	 */
	mouseOffset : function(event)
	{
		event = ToolMan.events().fix(event);
		if (event.pageX >= 0 || event.pageX < 0)
		{
			return this.create(event.pageX, event.pageY);
		} else if (event.clientX >= 0 || event.clientX < 0)
		{
			return this.mousePosition(event).plus(this.scrollOffset());
		}
	},

	_size : function(element)
	{
		/* TODO: move to a Dimension class */
		return this.create(element.offsetWidth, element.offsetHeight);
	},

	_offset : function(element)
	{
		return this.create(element.offsetLeft, element.offsetTop);
	}
};

/**
 * Constructor for _ToolManCoordinate
 */
/// removed factory pointer
/*
function _ToolManCoordinate(factory, x, y)
{
	ToolMan.coordinates() = factory;
	this.x = isNaN(x) ? 0 : x;
	this.y = isNaN(y) ? 0 : y;
}
*/
function _ToolManCoordinate(x, y)
{
	this.x = isNaN(x) ? 0 : x;
	this.y = isNaN(y) ? 0 : y;
}


/**
 * All the member functions of type _ToolManCoordinate, excellent technique
 */

_ToolManCoordinate.prototype = 
{
	toString : function()
	{
		return "(" + this.x + "," + this.y + ")";
	},

	plus : function(that)
	{
		return ToolMan.coordinates().create(this.x + that.x, this.y + that.y);
	},

	minus : function(that)
	{
		return ToolMan.coordinates().create(this.x - that.x, this.y - that.y);
	},

	min : function(that)
	{
		return ToolMan.coordinates().create(
				Math.min(this.x , that.x), Math.min(this.y , that.y));
	},

	max : function(that)
	{	
		return ToolMan.coordinates().create(
				Math.max(this.x , that.x), Math.max(this.y , that.y));
	},

	constrainTo : function (one, two)
	{
		var min = one.min(two);
		var max = one.max(two);

		return this.max(min).min(max);
	},

	distance : function (that)
	{
		return Math.sqrt(Math.pow(this.x - that.x, 2) + Math.pow(this.y - that.y, 2));
	},

	reposition : function(element)
	{
		element.style["top"] = this.y + "px";
		element.style["left"] = this.x + "px";
	},
	
	leftOf : function (that)
	{
		return this.x < that.x;
	}, 

	rightOf : function (that)
	{
		return this.x > that.x;
	},
	
	topOf : function (that)
	{
		return this.y < that.y;
	},
	
	bottomOf : function (that)
	{
		return this.y > that.y;
	}
};
